home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / Spinning Cursor 1.1 / Spinning Cursor Library Source / Source ƒ / SpinLib.c < prev   
Encoding:
C/C++ Source or Header  |  1995-06-26  |  7.0 KB  |  302 lines  |  [TEXT/KAHL]

  1. /*
  2.     SpinLib.c
  3.     
  4.     Code for spinning a beachball cursor.
  5.     
  6.     History:
  7.         06/01/95 - dn - Modified to use the Universal Headers.
  8. */
  9.  
  10. #include "SpinLibInterns.h"
  11.  
  12. #include <Traps.h>
  13. #include <GestaltEqu.h>
  14. #include <Think.h>
  15.  
  16. /*
  17.     To build a shared library from this project, you must do two things:
  18.     
  19.     1. Add the interfacelib.xcoff file to the project
  20.     2. move the next line out of this comment:
  21.         
  22.         #pragma lib_export list SpinInit, SpinStart, SpinStop, SpinSpinning, SpinCleanup
  23. */
  24.  
  25. #if USESROUTINEDESCRIPTORS
  26. #define UniversalHdrs
  27. #else
  28. #define NotUniversalHdrs
  29. #endif
  30.  
  31. #ifdef NotUniversalHdrs
  32. #ifndef CrsrBusy
  33. #define CrsrBusy  0x8CD                /*[GLOBAL VAR]  Cursor locked out? [byte]*/
  34. #endif
  35. #endif /* NotUniversalHdrs */
  36.  
  37. #define kBaseSpinCurs 29000
  38.  
  39. #ifdef NotUniversalHdrs
  40. pascal long __GetVBLRec (void);
  41. pascal long __GetVBLRec (void)= 0x2E88;
  42. #endif /* NotUniversalHdrs */
  43.  
  44. CursorTask            gCursTask;                        /* Global structure */
  45. Boolean                gCursInstalled = false;                /* installation global */
  46. Boolean                gCursInited=false;
  47.  
  48. /*
  49.     SpinInit
  50.     
  51.     Loads the cursors and sets up the spinning stuff...
  52. */
  53. OSErr SpinInit(void){
  54.     Handle h;
  55.     short i;
  56.     OSErr err;
  57.     
  58.     if (gCursInited)
  59.         return noErr;
  60.         
  61.     gCursInstalled = false;                            /* we are not installed yet */
  62.     gCursInited=false;
  63.     
  64.     /* allocate cursor memory */
  65.     gCursTask.cursors=(CursHandle *)NewPtr (8*sizeof (CursHandle));
  66.     
  67.     gCursTask.value=0;
  68.     
  69.     for (i=0; i < 8; i++) {                            /* cycle through the rest */
  70.             
  71.         h = (Handle)GetCursor (kBaseSpinCurs+i);            /* black and white */
  72.             
  73.         if (h == nil)                                /* did we get the cursor */
  74.             return ResError();                        /* if no, return error */
  75.         
  76.         DetachResource(h);
  77.         HNoPurge (h);                                /* force it unpurgeable */
  78.         HLockHi (h);                                /* and lock it high */
  79.         
  80.         gCursTask.cursors[i]=(CursHandle)h;
  81.     }
  82.     
  83.     gCursInited=true;
  84.     
  85.     return noErr;
  86. }
  87.  
  88. /*
  89.     SpinStart
  90.     
  91.     Starts the spinning of the beachball.
  92. */
  93. OSErr SpinStart(short direction){
  94.     OSErr        err;                                    /* returnable error */
  95.     short        i;                                    /* dummy counter */
  96.     Handle        h;
  97.     
  98.     if (!gCursInited)
  99.         return paramErr;
  100.         
  101.     if (gCursInstalled)                                    /* if we are already installed, */
  102.         return noErr; // do nothing...
  103.             
  104.     if (direction==0)
  105.         direction=1;
  106.     
  107.     if (direction>1)
  108.         direction=1;
  109.     if (direction<-1)
  110.         direction=-1;
  111.     
  112.     gCursTask.direction=direction;
  113.     
  114.     gCursTask.vblTask.qType = vType;                        /* set up the VBL task record */
  115.     
  116. #ifdef NotUniversalHdrs
  117.     gCursTask.vblTask.vblAddr=(ProcPtr)SpinTask;
  118. #else
  119.     {
  120.         VBLUPP spinUPP;
  121.         spinUPP=NewVBLProc(SpinTask); // get the Universal Proc Ptr for a VBL task
  122.         
  123.         gCursTask.vblTask.vblAddr = spinUPP;
  124.     }
  125. #endif /* NotUniversalHdrs */
  126.     
  127.     gCursTask.vblTask.vblCount = 20;
  128.     gCursTask.vblTask.vblPhase = 0;
  129.     gCursTask.vblA5 = SetCurrentA5();
  130.     gCursTask.vblKeyTag=(long)('NebS');
  131.     
  132.     err = VInstall ((QElemPtr)&gCursTask.vblTask);            /* install the VBL task */
  133.         
  134.     if (err)
  135.         return err;                                    /* if errors, return them, else */
  136.     else {
  137.         gCursInstalled = true;                            /* declare the task installed */
  138.         return noErr;                                    /* and return no error */
  139.     }
  140. }
  141.  
  142. /*
  143.     SpinTask
  144.     
  145.     This is the meat and bones of the spinning cursor calls.  When the VBL task count (vblCount) goes to zero, the
  146.     Vertical Retrace Manager will call SpinCursor(). Our job will be to set the cursor to the current frame, and then
  147.     to advance the frame. The thing to remember is that we are executed during interrupt, and we are not allowed to
  148.     use Memory Manager calls... as well as a billion other things.
  149.     
  150.     Another cool thing to note is that at the time of our interrupt, a pointer to the installed VBL task will be
  151.     placed in A0. Since we installed with some more globals attached, these will also be available to us; kind of
  152.     a sneaky way around the messed up A5 problem.
  153.     
  154.     Also remember that the vblCount is zero at this time. If we leave this function without returning a nonzero value,
  155.     the task will never return to SpinCursor again. So, we articulately return the vblCount to frequency, which is
  156.     why the task happens so regulary...
  157. */
  158. pascal void SpinTask(void){
  159.     CursorTaskPtr        taskPtr;
  160.     Boolean            busy;
  161.     CursPtr            cp;
  162.     
  163. #ifdef NotUniversalHdrs
  164.     taskPtr=(CursorTaskPtr)__GetVBLRec();
  165.     /*    
  166.         This is how we used to get the VBL record.
  167.     */
  168. #else
  169.     short            doNext=1;
  170.     QElemPtr            qep;
  171.     QHdrPtr            qh;
  172.     
  173.     /*
  174.         This is the Universal Header way to get to the queue element...  The queue
  175.         must be searched from the head to the end looking for our queue element.  If the
  176.         element can't be found then taskPtr is set to NULL.
  177.     */
  178.     
  179.     qh=GetVBLQHdr();    // get the head of the queue...
  180.     qep=qh->qHead;        // get the first element in the queue...
  181.     
  182.     do {
  183.         taskPtr=(CursorTaskPtr)qep; // make our ptr out of the elem ptr...
  184.         
  185.         if ((taskPtr->vblKeyTag)==((long)'NebS')){
  186.             // this is our item...
  187.             doNext=0;
  188.         } else {
  189.             // this is not our item...
  190.             if (qep->qLink!=(QElemPtr)NULL){
  191.                 // but not the end of the list...
  192.                 qep=qep->qLink;
  193.             } else {
  194.                 // this is the end of the list
  195.                 // make each of the pointers point to null
  196.                 qep=(QElemPtr)NULL;
  197.                 taskPtr=(CursorTaskPtr)NULL;
  198.                 
  199.                 // and flag the end of the loop...
  200.                 doNext=0;
  201.             }
  202.         }
  203.     } while (doNext);
  204.     
  205.     if (taskPtr==(CursorTaskPtr)NULL)
  206.         return;    // unable to continue since we don't have a pointer to our task (oops)!
  207. #endif /* NotUniversalHdrs */
  208.  
  209. #ifdef NotUniversalHdrs
  210.     // this is the old way...
  211.     busy = (*(Boolean *)CrsrBusy);                        /* determine the cursor state */
  212. #else
  213.     // this is the universal headers way...
  214.     busy= (Boolean)LMGetCrsrBusy();                        /* determine the cursor state */
  215. #endif /* NotUniversalHdrs */
  216.     
  217.     if (!busy) {                                        /* if it is available to us */
  218.                                                     /* set the cursor and frame advance */
  219.         cp=(CursPtr)(*(taskPtr->cursors[taskPtr->value]));
  220.         
  221.         SetCursor(cp);
  222.         
  223.         taskPtr->value += taskPtr->direction;
  224.             
  225.         if (taskPtr->value>7)
  226.             taskPtr->value=0;
  227.         
  228.         if (taskPtr->value<0)
  229.             taskPtr->value=7;
  230.     }
  231.  
  232.     taskPtr->vblTask.vblCount = 3;        /* restore the VBL task */
  233. }
  234.  
  235. /*
  236.     SpinStop
  237.     
  238.     Stops the spinning of the cursor.
  239. */
  240. OSErr SpinStop(void){
  241.     OSErr            err;
  242.     short            i;
  243.     CursPtr            arrowPtr;
  244.  
  245.     if (!gCursInstalled)                                    /* if we were not installed, */
  246.         return noErr;                                    /* alert them and exit */
  247.     
  248.     err = VRemove ((QElemPtr)&gCursTask.vblTask);            /* remove the VBL task */
  249.     gCursInstalled=false;
  250.     
  251.     
  252. #ifdef NotUniversalHdrs
  253.     arrowPtr=&arrow;
  254. #else
  255.     arrowPtr=&(qd.arrow);    
  256. #endif
  257.     
  258.     SetCursor (arrowPtr);                                /* restore the cursor to an arrow */
  259.     
  260.     return err;
  261. }
  262.  
  263. /*
  264.     SpinSpinning
  265.     
  266.     returns state of the cursor.
  267. */
  268. Boolean SpinSpinning(void){
  269.     return gCursInstalled;
  270. }
  271.  
  272. /*
  273.     SpinCleanup
  274.     
  275.     Dispose of the memory being used by the spinning cursors...
  276. */
  277. OSErr SpinCleanup(void){
  278.     short i;
  279.     OSErr err;
  280.     
  281.     if (gCursInstalled)
  282.         SpinStop();
  283.     
  284.     if (!gCursInited)
  285.         return noErr;
  286.         
  287.     for (i=0;i<8;i++){
  288.         HUnlock((Handle)(gCursTask.cursors[i]));
  289.         HPurge((Handle)(gCursTask.cursors[i]));
  290.         DisposeHandle((Handle)gCursTask.cursors[i]);
  291.     }
  292.     
  293.     DisposePtr((Ptr)(gCursTask.cursors));
  294.  
  295. #ifndef NotUniversalHdrs
  296.     // need to get rid of the routine descriptor...
  297.     DisposeRoutineDescriptor(gCursTask.vblTask.vblAddr);
  298. #endif /* NotUniversalHdrs */
  299.     
  300.     return noErr;                                        /* and return no error */
  301. }
  302.